﻿using ChartDirector;
using QuMianChaZhi.Contour;
using QuMianChaZhi.MyContour;
using QuMianChaZhi.SurfaceInterpolation;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace QuMianChaZhi
{
    public partial class Form1 : Form
    {
        public List<Point> mInitPoint = new List<Point>();

        double AverageValue = 1;
        public Form1()
        {
            InitializeComponent();

            init();
        }


        private ReadInTemp ReadInData { get; set; }


        public List<ContourSurface> contourLines { get; set; }

        private void init()
        {
            //OpenCSV(@"E:\Test\WangWanJiangChaZhi\QuMianChaZhi\AAA.csv");

            //ReadInData = OpenResultCSVFile(@"E:\Test\WangWanJiangChaZhi\QuMianChaZhi\result2.csv");


            //Contour.ContourMethods methods = new Contour.ContourMethods();
            //contourLines = methods.GenerateTrianges(ReadInData);

            ReadInData = new ReadInTemp();

            contourLines = new List<ContourSurface>();

        }


        /// <summary>
        /// 打开设备导出的原始测试数据
        /// X Axis,Y Axis,Z
        /// 0,     0,     0.02221
        /// 18,    0,     0.02207
        /// 36,    0,     0.02043
        // /12.73, 12.73, 0.02239
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public List<Point> OpenDeviceOutputCSV(string filePath)
        {
            List<Point> mInputPoint = new List<Point>();
            Encoding encoding = Encoding.ASCII;//

            FileStream fs = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);

            //StreamReader sr = new StreamReader(fs, Encoding.UTF8);
            StreamReader sr = new StreamReader(fs, encoding);
            //string fileContent = sr.ReadToEnd();
            //encoding = sr.CurrentEncoding;
            //记录每次读取的一行记录
            string strLine = "";
            //记录每行记录中的各字段内容
            string[] aryLine = null;
            string[] tableHead = null;
            //标示列数
            int columnCount = 0;
            //标示是否是读取的第一行
            bool IsFirst = true;

            //跳过第一行
            strLine = sr.ReadLine();

            double zTotal = 0;
            int count = 0;

            //逐行读取CSV中的数据
            while ((strLine = sr.ReadLine()) != null)
            {
                aryLine = strLine.Split(',');

                double x = double.Parse(aryLine[0]);
                double y = double.Parse(aryLine[1]);
                double z = double.Parse(aryLine[2]);

                zTotal += z;

                mInputPoint.Add(new Point() { x = x, y = y, z = z });
            }
            sr.Close();
            fs.Close();

            AverageValue = zTotal / mInputPoint.Count();

            return mInputPoint;
        }


        public ReadInTemp ParseSurfaceRawData(double[,] rawdata, int width, int height)
        {
            double[][] rets = new double[height][];


            double max = double.MinValue;
            double min = double.MaxValue;

            Dictionary<string, int> elementCount = new Dictionary<string, int>();

            SortedDictionary<int, int> ValueCount = new SortedDictionary<int, int>();

            double[] arrayRawDatas = new double[width * height];
            int arrayIndex = 0;

            int xIndex = 0;
            for (int row = 0; row < height; row++)
            {


                rets[xIndex] = new double[width];

                for (int yIndex = 0; yIndex < width; yIndex++)
                {
                    double zValueIn = rawdata[row, yIndex];

                    arrayRawDatas[arrayIndex++] = zValueIn;

                    //注意平均值
                    // int zValue =  (int)((zValueIn - AverageValue) * 1000);

                    //int zValue = (int)((zValueIn) * 100000);

                    rets[xIndex][yIndex] = zValueIn;

                    //if (ValueCount.ContainsKey(zValue))
                    //{
                    //    ValueCount[zValue]++;
                    //}
                    //else
                    //{
                    //    ValueCount.Add(zValue, 1);
                    //}

                    //String key = zValue.ToString("f2");

                    //if (elementCount.ContainsKey(key))
                    //{
                    //    elementCount[key]++;
                    //}
                    //else
                    //{
                    //    elementCount.Add(key, 1);
                    //}

                    if (zValueIn > max)
                    {
                        max = zValueIn;
                    }

                    if (zValueIn < min)
                    {
                        min = zValueIn;
                    }
                }

                xIndex++;

            }

            string whoIsMax = "0";
            int whoIsMaxValue = -10000;

            foreach (var item in elementCount)
            {
                if (item.Value > whoIsMaxValue)
                {
                    whoIsMax = item.Key;
                }
            }

            ReadInTemp retTemp = new ReadInTemp();
            retTemp.RawData = rets;
            retTemp.RawDataArray = arrayRawDatas;
            retTemp.Max = max;
            retTemp.Min = min;
            retTemp.Mid = double.Parse(whoIsMax);

            retTemp.W = width;
            retTemp.H = height;

            retTemp.ValueCount = ValueCount;

            return retTemp;
        }


        public double[,] OpenResultCSVFile(string filePath)
        {

            double[,] ret = new double[101, 101];
            //double[][] rets = new double[101][];

            Encoding encoding = Encoding.ASCII;//

            FileStream fs = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);

            //StreamReader sr = new StreamReader(fs, Encoding.UTF8);
            StreamReader sr = new StreamReader(fs, encoding);
            //string fileContent = sr.ReadToEnd();
            //encoding = sr.CurrentEncoding;
            //记录每次读取的一行记录
            string strLine = "";
            //记录每行记录中的各字段内容
            string[] aryLine = null;
            string[] tableHead = null;
            //标示列数
            int columnCount = 0;
            //标示是否是读取的第一行
            bool IsFirst = true;
            //逐行读取CSV中的数据


            double max = -100000;
            double min = 100000;

            Dictionary<string, int> elementCount = new Dictionary<string, int>();

            SortedDictionary<int, int> ValueCount = new SortedDictionary<int, int>();



            int xIndex = 0;
            while ((strLine = sr.ReadLine()) != null)
            {
                aryLine = strLine.Split(',');

                //rets[xIndex] = new double[101];

                for (int yIndex = 0; yIndex < 80; yIndex++)
                {
                    if (String.IsNullOrEmpty(aryLine[yIndex]))
                        break;

                    double zValueIn = double.Parse(aryLine[yIndex]);


                    ret[xIndex, yIndex] = zValueIn;
                }

                xIndex++;
                if (xIndex == 80)
                    break;
            }
            sr.Close();
            fs.Close();

            return ret;
        }

        private int beta { get; set; }   //1 or 2



        /// <summary>
        /// 将DataTable中数据写入到CSV文件中
        /// </summary>
        /// <param name="dt">提供保存数据的DataTable</param>
        /// <param name="fileName">CSV的文件路径</param>
        public static void SaveCSV(double[,] dt, string fullPath)
        {
            FileInfo fi = new FileInfo(fullPath);
            if (!fi.Directory.Exists)
            {
                fi.Directory.Create();
            }
            FileStream fs = new FileStream(fullPath, System.IO.FileMode.Create, System.IO.FileAccess.Write);
            //StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.Default);
            StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
            string data = "";
            //写出各行数据
            for (int i = 0; i < 100; i++)
            {
                data = "";
                for (int j = 0; j < 100; j++)
                {
                    string str = dt[i, j].ToString();

                    data += str;
                    if (j < 101 - 1)
                    {
                        data += ",";
                    }
                }
                sw.WriteLine(data);
            }
            sw.Close();
            fs.Close();
        }


        public Color RainbowNumberToColor(float number)
        {
            byte r = 0, g = 0, b = 0;
            if (number < 1 / 6f)
            {
                // Mostly red with some green.
                r = 255;
                g = (byte)(r * (number - 0) / (2 / 6f - number));
            }
            else if (number < 2 / 6f)
            {
                // Mostly green with some red.
                g = 255;
                r = (byte)(g * (2 / 6f - number) / (number - 0));
            }
            else if (number < 3 / 6f)
            {
                // Mostly green with some blue.
                g = 255;
                b = (byte)(g * (2 / 6f - number) / (number - 4 / 6f));
            }
            else if (number < 4 / 6f)
            {
                // Mostly blue with some green.
                b = 255;
                g = (byte)(b * (number - 4 / 6f) / (2 / 6f - number));
            }
            else if (number < 5 / 6f)
            {
                // Mostly blue with some red.
                b = 255;
                r = (byte)(b * (4 / 6f - number) / (number - 1f));
            }
            else
            {
                // Mostly red with some blue.
                r = 255;
                b = (byte)(r * (number - 1f) / (4 / 6f - number));
            }
            return Color.FromArgb(r, g, b);
        }

        // Map a value to a rainbow color.
        private Color MapRainbowColor(double value,
            double min_value, double max_value
           )
        {
            byte red, green, blue;
            // Convert into a value between 0 and 1023.
            int int_value = (int)(1023 * (value - min_value) /
                (max_value - min_value));

            // Map different color bands.
            if (int_value < 256)
            {
                // Red to yellow. (255, 0, 0) to (255, 255, 0).
                red = 255;
                green = (byte)int_value;
                blue = 0;
            }
            else if (int_value < 512)
            {
                // Yellow to green. (255, 255, 0) to (0, 255, 0).
                int_value -= 256;
                red = (byte)(255 - int_value);
                green = 255;
                blue = 0;
            }
            else if (int_value < 768)
            {
                // Green to aqua. (0, 255, 0) to (0, 255, 255).
                int_value -= 512;
                red = 0;
                green = 255;
                blue = (byte)int_value;
            }
            else
            {
                // Aqua to blue. (0, 255, 255) to (0, 0, 255).
                int_value -= 768;
                red = 0;
                green = (byte)(255 - int_value);
                blue = 255;
            }

            return Color.FromArgb(red, green, blue);
        }

        private void drawBasicPoints(Graphics g)
        {
            if (ReadInData == null || ReadInData.ValueCount == null)
            {
                return;
            }
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            double xMin = 10000;
            double xMax = -100000;

            foreach (var item in ReadInData.ValueCount)
            {
                //if(item.Value < 10)
                //{
                //    continue;
                //}

                if (item.Key > xMax)
                    xMax = item.Key;

                if (item.Key < xMin)
                {
                    xMin = item.Key;
                }
            }


            xMin = 0;
            xMin = 3500;

            double colourOffset = xMax - xMin;

            for (int x = 0; x < 100; x += 1)
            {
                for (int y = 0; y < 100; y += 1)
                {
                    double ptelement = ReadInData.RawData[x][y];

                    double fColour = ((ptelement - xMin) / colourOffset) * 255;

                    int xcolour = (int)fColour;

                    //if (xcolour < 0) xcolour = 0;
                    //if (xcolour > 255) xcolour = 255;

                    //Color clr = Color.FromArgb(255 - xcolour, 0, xcolour);

                    //if (xcolour > 110 && xcolour <130)
                    //{
                    //    clr = Color.FromArgb(0, 100 + xcolour, 0);
                    //}

                    float percentage = (float)((float)(xcolour) / 255.0);

                    Color clr = MapRainbowColor(ptelement, xMax, xMin);//RainbowNumberToColor(percentage);


                    double xi = x - 50;
                    double yi = y - 50;


                    if (xi * xi + yi * yi > 50 * 50)
                    {
                        continue;
                    }


                    int rx = x * 5;
                    int ry = y * 5;

                    Brush brsh = new SolidBrush(clr);
                    g.FillEllipse(brsh, rx - 4, ry - 4, 8, 8);
                }
            }
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Size size = pictureBox1.Size;

            //drawBasicPoints(g);

            //if (ReadInData == null || ReadInData.ValueCount == null)
            //{
            //    return;
            //}

            //DrawOnControl.Draw(g, ReadInData);
            //DrawContourLines(g);

            DrawContourLines2(g);

        }

        private void DrawContourLines(Graphics g)
        {
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            double max = -100000;
            double min = 100000;
            foreach (ContourSurface face in contourLines)
            {
                if (face.Value > max)
                    max = face.Value;

                if (face.Value < min)
                {
                    min = face.Value;
                }
            }

            double colourOffset = max - min;
            foreach (ContourSurface face in contourLines)
            {
                double value = face.Value;
                double fColour = ((value - min) / colourOffset) * 255;

                int xcolour = (int)fColour;

                if (xcolour < 0) xcolour = 0;
                if (xcolour > 255) xcolour = 255;

                Color clr = Color.FromArgb(255 - xcolour, xcolour, 0);


                List<ContourLine> lines = face.Lines;

                foreach (ContourLine line in lines)
                {
                    List<VPoint> points = line.Points;


                    List<PointF> netPoints = new List<PointF>();

                    Pen p = new Pen(clr, 2);
                    for (int start = 0; start < points.Count - 1; start++)
                    {
                        VPoint p1 = points[start];
                        VPoint p2 = points[start + 1];



                        PointF pf1 = new PointF(p1.X * 5, p1.Y * 5);

                        PointF pf2 = new PointF(p2.X * 5, p2.Y * 5);

                        // g.FillEllipse(Brushes.Black, pf1.X - 2, pf1.Y - 2, 4,4);
                        // g.FillEllipse(Brushes.Yellow, pf2.X - 3, pf2.Y - 3, 6,6);

                        netPoints.Add(pf1);

                        if (start == points.Count - 2)
                        {
                            netPoints.Add(pf2);
                        }

                        //g.DrawLine(p, p1.X * 5, p1.Y * 5, p2.X*5, p2.Y*5);

                    }

                    if (netPoints.Count > 2)
                    {
                        g.DrawCurve(p, netPoints.ToArray());
                    }
                }


            }



        }


        double[,] m_calculaterdRet = null;
        private void button_OpenInputData_Click(object sender, EventArgs e)
        {
            if (openFileDialog_InputData.ShowDialog() == DialogResult.OK)
            {
                String fileName = openFileDialog_InputData.FileName;

                mInitPoint = OpenDeviceOutputCSV(fileName);

                dv_deviceInput.DataSource = mInitPoint;


                InterpolationMethodOne one = new InterpolationMethodOne();
                //InterpolationMethodTwo one = new InterpolationMethodTwo();
                //double[,] ret = one.CalculateInterpolation(mInitPoint);

                //InterpolationMethod one = new InterpolationMethodThree();



                // m_calculaterdRet = one.CalculateInterpolation(mInitPoint);


                //ReadInData = ParseSurfaceRawData(m_calculaterdRet, 100, 100);


                // pictureBox1.Invalidate();

            }
        }

        /// <summary>
        /// 等高线
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            if (openFileDialog_InputData.ShowDialog() == DialogResult.OK)
            {
                String fileName = openFileDialog_InputData.FileName;



                var rawdatas = OpenResultCSVFile(fileName);


                ReadInData = ParseSurfaceRawData(rawdatas, 100, 100);


                Contour.ContourMethods methods = new Contour.ContourMethods();
                contourLines = methods.GenerateTrianges(ReadInData);


                pictureBox1.Invalidate();

            }
        }

        /// <summary>
        /// 导出文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {

            beta = 1;

            InterpolationMethodFour one = new InterpolationMethodFour();

            //InterpolationMethod one = new InterpolationMethodThree();

            double[,] ret = one.CalculateInterpolation(mInitPoint);

            //ReadInData = ParseSurfaceRawData(ret, 100, 100);

            pictureBox1.Invalidate();

            //if (m_calculaterdRet == null)
            //   return;

            saveFileDialog_OutputData.Filter = "csv File(*.csv)|*.csv";
            saveFileDialog_OutputData.FilterIndex = 1;
            saveFileDialog_OutputData.RestoreDirectory = true;

            if (saveFileDialog_OutputData.ShowDialog() == DialogResult.OK)
            {
                string filepath = saveFileDialog_OutputData.FileName.ToString();

                SaveCSV(ret, filepath);

                // SaveCSV(ret, @"E:\Test\WangWanJiangChaZhi\QuMianChaZhi\result2.csv");
            }


        }

        private void button_show_fit_result_Click(object sender, EventArgs e)
        {
            if (openFileDialog_InputData.ShowDialog() == DialogResult.OK)
            {
                String fileName = openFileDialog_InputData.FileName;

                var rawdatas = OpenResultCSVFile(fileName);

                ReadInData = ParseSurfaceRawData(rawdatas, 80, 80);

                //Contour.ContourMethods methods = new Contour.ContourMethods();
                //contourLines = methods.GenerateTrianges(ReadInData);


                pictureBox1.Invalidate();

                WinChartViewer chart = DrawContour.Draw(ReadInData);

                chart.Image.Save(@"E:\\xy.jpg");
                panel_host.Controls.Clear();
                chart.Dock = DockStyle.Fill;
                panel_host.Controls.Add(chart);
            }
        }

        private void btKrigingTest_Click(object sender, EventArgs e)
        {
            if (mInitPoint.Count == 0)
            {
                MessageBox.Show("先打开初始测试数据");
                return;
            }

            List<double> t = new List<double>();
            List<double> x = new List<double>();
            List<double> y = new List<double>();

            foreach (var pt in mInitPoint)
            {
                x.Add(pt.x);
                y.Add(pt.y);
                t.Add(pt.z);
            }

            InterPolationKriging kriging = new InterPolationKriging();
            InterPolationKriging.Variogram variogram = kriging.train(t, x, y, "gaussian", 0, 100);

            int[][] range = new int[4][];
            range[0] = new int[] { 50, 50};
            range[1] = new int[] { -50, 50 };
            range[2] = new int[] { -50, -50 };
            range[3] = new int[] { 50, -50 };
            

            //一个像素的宽度
            int interPixWidth = 1;
            InterPolationKriging.GridResult grid = kriging.grid(range, variogram, 1);


            saveFileDialog_OutputData.Filter = "csv File(*.csv)|*.csv";
            saveFileDialog_OutputData.FilterIndex = 1;
            saveFileDialog_OutputData.RestoreDirectory = true;

            if (saveFileDialog_OutputData.ShowDialog() == DialogResult.OK)
            {
                string filepath = saveFileDialog_OutputData.FileName.ToString();

                SaveCSV(grid.A, filepath);

                // SaveCSV(ret, @"E:\Test\WangWanJiangChaZhi\QuMianChaZhi\result2.csv");
            }

            var m = variogram.M;
            var k = variogram.K;

        }

        /// <summary>
        /// 自绘等高线
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelfDrawContourLine_Click(object sender, EventArgs e)
        {
            if (openFileDialog_InputData.ShowDialog() == DialogResult.OK)
            {
                String fileName = openFileDialog_InputData.FileName;



                var rawdatas = OpenResultCSVFile(fileName);


                myContourImpl = new MyContourImpl();

                var ReadInData = myContourImpl.ParseSurfaceRawData(rawdatas, 80, 80);

                myContourImpl.IsoBand();

                //var ReadInData = ParseSurfaceRawData(rawdatas, 80, 80);


                //Contour.ContourMethods methods = new Contour.ContourMethods();
                //contourLines = methods.GenerateTrianges(ReadInData);


                pictureBox1.Invalidate();

            }
        }


        private MyContourImpl myContourImpl { get; set; }

        private void DrawContourLines2(Graphics g)
        {
            if(myContourImpl == null)
            {
                return;
            }

            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;


            int Width = pictureBox1.Width;
            int c = pictureBox1.Height;


            double oneGridPixWidth = (double)Width / 80.0;

            double oneGridPixHeight = (double)Height / 80.0;


            int ColorIndex = 0;

            foreach (var oneSameColorAreas in myContourImpl.ISOBandAreas)
            {
                Color cl = myContourImpl.RainbowColors[ColorIndex++];
                Brush bru = new SolidBrush(cl);
                foreach (var eachArea in oneSameColorAreas)
                {
                    List<PointF> netPoints = new List<PointF>();

                    foreach(var onePoint in eachArea)
                    {
                        PointF ptF = new PointF((float)(onePoint[0] * oneGridPixWidth), (float)(onePoint[1] * oneGridPixHeight));

                        netPoints.Add(ptF);
                    }

                    
                    g.FillPolygon(bru, netPoints.ToArray());
                }
            }



            



        }
    }
    
}
